/***************************************************************************
 *   Copyright (C) 2008 by Tomasz Dubik                                    *
 *   tdubik@gmail.com                                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <QDebug>
#include <memory>
#include <cassert>

#include "tinyxml/tinyxml.h"
#include "taskcontainer.h"

namespace Tasks
{
    TaskContainer::TaskContainer():m_CurrentID(1)
    {
    }
    
    TaskContainer::~TaskContainer()
    {
        vector<Task*>::iterator it = m_Tasks.begin();
        while( it != m_Tasks.end())
        {
            delete *it;
            it++;
        }
        m_Tasks.clear();
    }
    /*
    TaskContainer* TaskContainer::instance()
    {
        static std::auto_ptr<TaskContainer> spTC (new TaskContainer());
        return spTC.get();
    }
*/
    UID TaskContainer::addTask(const string& text,int progress,UID parentID)
    {
        return addTask(text, progress, parentID, time(NULL));
    }
    
    UID TaskContainer::addTask(const string& text, int progress, UID parentID, time_t modifyTime, UID selfID )
    {
        qDebug() << Q_FUNC_INFO << QString::fromStdString(text) << "P: " << progress << "pID: " << parentID;
                
        Task* newTask = new Task();
        newTask->setText(text);
        newTask->setProgress(progress);
        newTask->setLastModify(modifyTime);

        if( selfID != 0 )
        {
            newTask->setID(selfID);
            if( selfID >= m_CurrentID )
                m_CurrentID = selfID+1;
        }
        else
            newTask->setID(m_CurrentID++);

        UID ID = newTask->id();
        if( parentID != 0)
        {
            Task* parent = findTask(parentID);
            if( parent )
            {
                newTask->setParent(*parent);
                parent->addTask(*newTask);
                delete newTask;
            }
            else
                qDebug() << "Parent not found"; //TODO:throw exception
        }
        else
            m_Tasks.push_back(newTask);
        return ID;
    }
    
    void TaskContainer::editTask(const string& text, UID ID )
    {
        qDebug() << Q_FUNC_INFO << QString::fromStdString(text)<< "ID:"<<ID;

        Task* task = findTask(ID);

        if( task )
        {
            task->setText(text);
        }
    }
    
    void TaskContainer::deleteTask(UID ID )
    {
        qDebug() << Q_FUNC_INFO << ID;

        Task* task = findTask(ID);
        assert(task);
        Task* parent = task->parent();
        if( parent )
        {                       
            parent->removeChild(task);
        }
        else
        {
            vector<Task*>::iterator it = m_Tasks.begin();
            while( it != m_Tasks.end() )
            {
                if( *it == task )
                {                    
                    task->deleteChilds();
                    m_Tasks.erase(it);
                    delete task;
                    task = NULL;
                    return;
                }
                ++it;
            }
        }
    }
    
    void TaskContainer::setTaskProgress(int value, UID ID)
    {
        qDebug() << Q_FUNC_INFO << value << "ID:" << ID;

        Task* task = findTask(ID);
        assert(task);
        task->setProgress(value);        
    }
    
    Task* TaskContainer::findTask(UID ID)
    {
        if( m_Tasks.size() )
        {
            vector<Task*>::iterator it = m_Tasks.begin();
            Task* result = NULL;
            while( it != m_Tasks.end() )
            {
                if(( result = (*it)->find( ID )) != NULL )
                    return result;
                ++it;
            }
        }
        cout << "TASK NOT FOUND";
        return NULL;
    }

    time_t TaskContainer::lastModifyTime( UID ID )
    {
        qDebug() << Q_FUNC_INFO << "ID:" << ID;

        Task* task = findTask(ID);
        assert(task);
        return task->lastModify();
    }

    void TaskContainer::save(const char* fileName)
    {

        TiXmlDocument doc;
        TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );
        doc.LinkEndChild( decl );

        TiXmlElement * root = new TiXmlElement("collection");
        doc.LinkEndChild( root );

        Task::Vector::iterator it = m_Tasks.begin();
        while( it != m_Tasks.end() )
        {            
            (*it)->save(root);
            ++it;
        }
        doc.SaveFile(fileName);
    }

    void TaskContainer::load(const char* filename)
    {

        TiXmlDocument doc(filename);
        if (!doc.LoadFile())
            return;

        TiXmlHandle hDoc(&doc);
        TiXmlElement* pElem;
        TiXmlHandle hRoot(0);

        pElem = hDoc.FirstChildElement("collection").Element();
        // should always have a valid root but handle gracefully if it does
        if (!pElem)
            return;

        // save this for later
        hRoot = TiXmlHandle(pElem);     
        pElem = hRoot.FirstChild( "item" ).Element();
        Task* newTask = NULL;                

        for( pElem; pElem; pElem=pElem->NextSiblingElement())
        {            
            newTask = new Task(pElem);
            m_Tasks.push_back(newTask);
        }
        calculateCurrentID();
        m_CurrentID++;
    }

    const Task::Vector& TaskContainer::TasksData()
    {
        return m_Tasks;
    }

    void TaskContainer::calculateCurrentID()
    {
        Task::Vector::iterator it = m_Tasks.begin();        
        while( it != m_Tasks.end())
        {
            (*it)->calculateCurrentID(m_CurrentID);
            ++it;
        }
    }
}
